// RUN: mlir-pdll %s -I %S -split-input-file | FileCheck %s

//===----------------------------------------------------------------------===//
// CompoundStmt
//===----------------------------------------------------------------------===//

// CHECK: Module
// CHECK: CompoundStmt
// CHECK:   |-LetStmt
// CHECK:   `-EraseStmt
Pattern {
  let root: Op;
  erase root;
}

// -----

//===----------------------------------------------------------------------===//
// EraseStmt
//===----------------------------------------------------------------------===//

// CHECK: Module
// CHECK: EraseStmt
// CHECK:   `-DeclRefExpr {{.*}} Type<Op>
Pattern {
  erase _: Op;
}

// -----

//===----------------------------------------------------------------------===//
// LetStmt
//===----------------------------------------------------------------------===//

// CHECK: Module
// CHECK: LetStmt
// CHECK:   `-VariableDecl {{.*}} Name<attrVar> Type<Attr>
// CHECK:     `Constraints`
// CHECK:       `-AttrConstraintDecl
// CHECK:   `-VariableDecl {{.*}} Name<var> Type<Op>
// CHECK:     `Constraints`
// CHECK:       `-OpConstraintDecl
// CHECK:         `-OpNameDecl
Pattern {
  let attrVar: Attr;
  let var: Op;
  erase var;
}

// -----

// Check for proper refinement between constraint types.

// CHECK: Module
// CHECK: LetStmt
// CHECK:   `-VariableDecl {{.*}} Name<var> Type<Op<dialect.op>>
// CHECK:     `Constraints`
// CHECK:       `-OpConstraintDecl
// CHECK:         `-OpNameDecl
// CHECK:       `-OpConstraintDecl
// CHECK:         `-OpNameDecl {{.*}} Name<dialect.op>
Pattern {
  let var: [Op, Op<dialect.op>];
  erase var;
}

// -----

// Check for proper conversion between initializer and constraint type.

// CHECK: Module
// CHECK: LetStmt
// CHECK:   `-VariableDecl {{.*}} Name<var> Type<Op<dialect.op>>
// CHECK:     `-DeclRefExpr {{.*}} Type<Op<dialect.op>>
// CHECK:       `-VariableDecl {{.*}} Name<input>
// CHECK:     `Constraints`
// CHECK:       `-OpConstraintDecl
// CHECK:         `-OpNameDecl
Pattern {
  let input: Op<dialect.op>;
  let var: Op = input;
  erase var;
}

// -----

// Check for proper conversion between initializer and constraint type.

// CHECK: Module
// CHECK: LetStmt
// CHECK:   `-VariableDecl {{.*}} Name<var> Type<Value>
// CHECK:     `-MemberAccessExpr {{.*}} Member<$results> Type<Value>
// CHECK:       `-DeclRefExpr {{.*}} Type<Op<dialect.op>>
// CHECK:         `-VariableDecl {{.*}} Name<input>
// CHECK:     `Constraints`
// CHECK:       `-ValueConstraintDecl
Pattern {
  let input: Op<dialect.op>;
  let var: Value = input;
  erase _: Op;
}

// -----

// Check for proper conversion between initializer and constraint type.

// CHECK: Module
// CHECK: LetStmt
// CHECK:   `-VariableDecl {{.*}} Name<var> Type<ValueRange>
// CHECK:     `-MemberAccessExpr {{.*}} Member<$results> Type<ValueRange>
// CHECK:       `-DeclRefExpr {{.*}} Type<Op<dialect.op>>
// CHECK:         `-VariableDecl {{.*}} Name<input>
// CHECK:     `Constraints`
// CHECK:       `-ValueRangeConstraintDecl
Pattern {
  let input: Op<dialect.op>;
  let var: ValueRange = input;
  erase _: Op;
}

// -----

// Check for proper handling of type constraints.

// CHECK: Module
// CHECK: LetStmt
// CHECK:   `-VariableDecl {{.*}} Name<var> Type<Value>
// CHECK:     `Constraints`
// CHECK:       `-ValueConstraintDecl
// CHECK:         `-DeclRefExpr {{.*}} Type<Type>
// CHECK:           `-VariableDecl {{.*}} Name<_> Type<Type>
// CHECK:             `Constraints`
// CHECK:               `-TypeConstraintDecl
Pattern {
  let var: Value<_: Type>;
  erase _: Op;
}

// -----

// Check for proper handling of type constraints.

// CHECK: Module
// CHECK: LetStmt
// CHECK:   `-VariableDecl {{.*}} Name<var> Type<ValueRange>
// CHECK:     `Constraints`
// CHECK:       `-ValueRangeConstraintDecl
// CHECK:         `-DeclRefExpr {{.*}} Type<TypeRange>
// CHECK:           `-VariableDecl {{.*}} Name<_> Type<TypeRange>
// CHECK:             `Constraints`
// CHECK:               `-TypeRangeConstraintDecl
Pattern {
  let var: ValueRange<_: TypeRange>;
  erase _: Op;
}

// -----

//===----------------------------------------------------------------------===//
// ReplaceStmt
//===----------------------------------------------------------------------===//

// CHECK: Module
// CHECK: `-ReplaceStmt
// CHECK:   `-DeclRefExpr {{.*}} Type<Op>
// CHECK:   ReplValues
// CHECK:     `-OperationExpr {{.*}} Type<Op<my_dialect.foo>>
Pattern {
  replace _: Op with op<my_dialect.foo>;
}

// -----

// CHECK: Module
// CHECK: `-ReplaceStmt
// CHECK:   `-DeclRefExpr {{.*}} Type<Op>
// CHECK:   ReplValues
// CHECK:     |-DeclRefExpr {{.*}} Type<Value>
// CHECK:     |-DeclRefExpr {{.*}} Type<ValueRange>
// CHECK:     `-MemberAccessExpr {{.*}} Member<$results> Type<ValueRange>
// CHECK:       `-OperationExpr {{.*}} Type<Op<my_dialect.foo>>
Pattern {
  replace _: Op with (_: Value, _: ValueRange, op<my_dialect.foo>);
}

// -----

//===----------------------------------------------------------------------===//
// RewriteStmt
//===----------------------------------------------------------------------===//

// CHECK: Module
// CHECK: `-RewriteStmt
// CHECK:   |-DeclRefExpr {{.*}} Type<Op>
// CHECK:   `-CompoundStmt
// CHECK:     |-OperationExpr {{.*}} Type<Op<my_dialect.some_op>>
// CHECK:     `-ReplaceStmt {{.*}}
// CHECK:       `-DeclRefExpr {{.*}} Type<Op>
// CHECK:       `ReplValues`
// CHECK:          `-OperationExpr {{.*}} Type<Op<my_dialect.foo>>
Pattern {
  rewrite root: Op with {
    op<my_dialect.some_op>;
    replace root with op<my_dialect.foo>;
  };
}
